package com.zcxy360.sandtable.service;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zcxy360.sandtable.domain.Course;
import com.zcxy360.sandtable.domain.CourseMapper;
import com.zcxy360.sandtable.domain.CourseStudent;
import com.zcxy360.sandtable.domain.CourseStudentMapper;
import com.zcxy360.sandtable.domain.User;
import com.zcxy360.sandtable.domain.UserExample;
import com.zcxy360.sandtable.domain.UserExample.Criteria;
import com.zcxy360.sandtable.domain.UserMapper;
import com.zcxy360.sandtable.exception.MyException;
import com.zcxy360.sandtable.util.ExcelUtil;
import com.zcxy360.sandtable.util.PasswordUtil;
import com.zcxy360.sandtable.util.ShiroUtil;
import com.zcxy360.sandtable.util.StringUtil;

@Transactional
@Service
public class UserService {

	@Autowired
	private UserMapper userMapper;
	@Autowired
	private CourseStudentMapper courseStudentMapper;
	@Autowired
	private CourseMapper courseMapper;

	public Object getByUserId(Integer userId) {
		return userMapper.selectByPrimaryKey(userId);
	}

	public Object list(User user, String key, String orderByClause, Integer pageNum, Integer pageSize,
			Integer navigatePages) {
		User loginUser = ShiroUtil.getUser();
		String loginRole = loginUser.getRole();
		if (!loginRole.equals("admin")) {
			if (loginRole.equals("manager")) {
				user.setCreatorId(null);
				user.setOrgId(loginUser.getOrgId());
			}
			if (loginRole.equals("teacher")) {
				user.setCreatorId(loginUser.getUserId());
				user.setOrgId(loginUser.getOrgId());
			}
		}
		PageHelper.startPage(pageNum, pageSize);
		List<User> users = userMapper.listWithExtra(user, StringUtil.wrapper(key), orderByClause);
		return new PageInfo<>(users, navigatePages);
	}

	public User post(User user) {
		String role = user.getRole();
		User loginUser = ShiroUtil.getUser();
		String loginRole = loginUser.getRole();
		if (!loginRole.equals("admin")) {
			user.setOrgId(loginUser.getOrgId());
		}
		if (loginRole.equals("manager")) {
			if (!role.equals("student") && !role.equals("teacher")) {
				throw new MyException("机构管理员只能创建学生和老师");
			}
		}
		if (loginRole.equals("teacher")) {
			if (!role.equals("student")) {
				throw new MyException("老师只能创建学生");
			}
		}
		user.setCreatorId(loginUser.getUserId());
		user.setPassword(user.getPhone().substring(3));
		PasswordUtil.encryptPassword(user);
		userMapper.insertSelective(user);
		return user;
	}

	public Object importUser(MultipartFile file, Integer orgId, String role, Integer courseId) {
		User loginUser = ShiroUtil.getUser();
		String loginRole = loginUser.getRole();
		if (!loginRole.equals("admin")) {
			orgId = loginUser.getOrgId();
		}
		if (loginRole.equals("manager")) {
			if (!role.equals("student") && !role.equals("teacher")) {
				throw new MyException("机构管理员只能创建学生和老师");
			}
		}
		if (loginRole.equals("teacher")) {
			if (!role.equals("student")) {
				throw new MyException("老师只能创建学生");
			}
		}
		InputStream inputStream = null;
		try {
			inputStream = file.getInputStream();
		} catch (IOException e) {
			e.printStackTrace();
			throw new MyException("读取上传文件失败");
		}
		List<User> users = new ArrayList<>();
		List<String> existsPhones = new ArrayList<>();
		List<String> phoneList = new ArrayList<>();
		List<String> idCardList = new ArrayList<>();
		User user;
		String phone;
		String idCard;
		String phoneRegex = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$";
		String idCardRegex = "(^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{2}[0-9Xx]$)";
		boolean phoneExist;
		boolean idCardExist;
		int index = 0;
		try {
			List<List<String>> lists = ExcelUtil.readStream(inputStream);
			for (List<String> list : lists) {
				index++;
				phone = list.get(2);
				idCard = list.get(3);
				if (phoneList.contains(phone)) {
					throw new MyException(phone + "重复");
				}
				if (idCardList.contains(idCard)) {
					throw new MyException(idCard + "重复");
				}
				phoneList.add(phone);
				idCardList.add(idCard);
				if (!phone.matches(phoneRegex)) {
					throw new MyException(phone + "不是正确的手机号");
				}
				if (!idCard.matches(idCardRegex)) {
					throw new MyException(idCard + "不是正确的身份证号");
				}
				phoneExist = !checkUnique(phone);
				idCardExist = !checkUnique(idCard);
				if (phoneExist && !idCardExist) {
					throw new MyException("第" + index + "条数据: " + phone + "在系统中已有对应账号,对应" + idCard + "不匹配");
				}
				if (idCardExist && !phoneExist) {
					throw new MyException("第" + index + "条数据: " + idCard + "在系统中已有对应账号,对应" + phone + "不匹配");
				}
				if (phoneExist && idCardExist) {
					UserExample ex = new UserExample();
					Criteria or = ex.or();
					or.andPhoneEqualTo(phone);
					or.andIdCardEqualTo(idCard);
					List<User> selectByExample = userMapper.selectByExample(ex);
					if (selectByExample.size() == 1) {
						if (selectByExample.get(0).getOrgId() != orgId) {
							throw new MyException("第" + index + "条数据: " + phone + "与" + idCard + "在系统中已存在,但却不是同一机构");
						}
						existsPhones.add(phone);
						continue;
					} else {
						throw new MyException("第" + index + "条数据: " + phone + "与" + phone + "在系统中已有数据,但却不是同一条数据");
					}
				}

				user = new User();
				user.setRealName(list.get(0));
				user.setSex(list.get(1).equals("男") ? 1 : 2);
				user.setPhone(phone);
				user.setIdCard(idCard);

				user.setOrgId(orgId);
				user.setRole(role);
				user.setCreatorId(loginUser.getUserId());
				user.setPassword(StringUtil.generateDefaultPassword(user.getPhone()));
				PasswordUtil.encryptPassword(user);
				users.add(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
			if (e instanceof MyException) {
				throw e;
			}
			throw new MyException("导入用户失败,请检查excel文件");
		}
		if (!users.isEmpty()) {
			userMapper.insertBatch(users);
		}

		if (courseId != null) {
			Course course = courseMapper.selectByPrimaryKey(courseId);
			if (course == null) {
				throw new MyException("没有此课程");
			}
			List<String> coursePhones = courseStudentMapper.selectPhonesByCourseId(courseId);
			existsPhones.removeAll(coursePhones);
			if (!existsPhones.isEmpty()) {
				List<String> phones = courseMapper.checkByExistsPhones(existsPhones);
				if (!phones.isEmpty()) {
					throw new MyException(phones + "有未完成课程");
				}
				List<User> existsUsers = userMapper.listByPhones(existsPhones);
				users.addAll(existsUsers);
			}
			if (!users.isEmpty()) {
				Integer personCount = course.getPersonCount();
				if (users.size() + coursePhones.size() > personCount) {
					throw new MyException("学生数量不能超过" + personCount);
				}
				List<CourseStudent> courseStudents = new ArrayList<>();
				CourseStudent courseStudent;
				for (User checkUser : users) {
					Integer userId = checkUser.getUserId();
					courseStudent = new CourseStudent();
					courseStudent.setUserId(userId);
					courseStudent.setCourseId(courseId);
					courseStudent.setIsAgree(true);
					courseStudents.add(courseStudent);
				}
				courseStudentMapper.insertBatch(courseStudents);
			}
		}
		return users;
	}

	public boolean update(User user) {
		User loginUser = ShiroUtil.getUser();
		String loginRole = loginUser.getRole();
		String role = user.getRole();

		if (!loginRole.equals("admin")) {
			user.setOrgId(loginUser.getOrgId());
		}
		if (loginRole.equals("manager")) {
			if (role != null && !(role.equals("student") || role.equals("teacher"))) {
				throw new MyException("机构管理员只能修改学生和老师");
			}
		}
		if (loginRole.equals("teacher")) {
			if (role != null && !role.equals("student")) {
				throw new MyException("老师只能修改学生");
			}
		}
		userMapper.updateByPrimaryKeySelective(user);
		return true;
	}

	public boolean delete(int[] userIds) {
		User loginUser = ShiroUtil.getUser();
		String loginRole = loginUser.getRole();
		Integer uOrgId = loginUser.getOrgId();
		String role;
		Integer orgId;
		User user;
		for (int userId : userIds) {
			user = userMapper.selectByPrimaryKey(userId);
			if (user == null) {
				continue;
			}
			role = user.getRole();
			orgId = user.getOrgId();
			if (!loginRole.equals("admin")) {
				if (!orgId.equals(uOrgId)) {
					throw new MyException("只能删除本机构账号");
				}
				if (loginRole.equals("teacher") && !role.equals("student")) {
					throw new MyException("老师只能删除学生");
				}
				if (loginRole.equals("manager") && !(role.equals("student") || role.equals("teacher"))) {
					throw new MyException("机构管理员只能删除学生和老师");
				}
			}
		}
		userMapper.deleteBatch(userIds);
		return true;
	}

	public boolean checkUnique(String username) {
		UserExample ex = new UserExample();
		ex.or().andUsernameEqualTo(username);
		ex.or().andPhoneEqualTo(username);
		ex.or().andIdCardEqualTo(username);
		return userMapper.countByExample(ex) == 0;
	}

	public User login(User user, boolean rememberMe) {
		UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword(), rememberMe);
		Subject subject = SecurityUtils.getSubject();
		subject.login(token);
		User loginUser = ShiroUtil.getUser();
		User forUpdateLastTime = new User();
		forUpdateLastTime.setUserId(loginUser.getUserId());
		forUpdateLastTime.setLastTime(new Date());
		userMapper.updateByPrimaryKeySelective(forUpdateLastTime);
		return loginUser;
	}

	public boolean logout() {
		Subject subject = SecurityUtils.getSubject();
		subject.logout();
		return true;
	}

	public boolean checkPassword(String password) {
		return PasswordUtil.checkPassword(password,ShiroUtil.getUser());
	}

	public boolean resetPassword(String phone, String password) {
		if(StringUtil.isNotEmpty(phone)) {
			User user = new User();
			user.setPhone(phone);
			user.setPassword(password);
			PasswordUtil.encryptPassword(user);
			UserExample ex = new UserExample();
			Criteria or = ex.or();
			or.andPhoneEqualTo(phone);
			userMapper.updateByExampleSelective(user, ex);
		}else {
			User loginUser = ShiroUtil.getUser();
			if(loginUser != null) {
				loginUser.setPassword(password);
				PasswordUtil.encryptPassword(loginUser);
				userMapper.updateByPrimaryKeySelective(loginUser);
				SecurityUtils.getSubject().logout();
			}
		}
		return true;
	}

	public User getUserByUsername(String username) {
		UserExample ex = new UserExample();
		ex.or().andUsernameEqualTo(username);
		ex.or().andPhoneEqualTo(username);
		ex.or().andIdCardEqualTo(username);
		List<User> list = userMapper.selectByExample(ex);
		return list.isEmpty() ? null : list.get(0);
	}

	public Set<String> getRolesByUsername(String username) {
		User loginUser = ShiroUtil.getUser();
		Set<String> set = new HashSet<>();
		set.add(loginUser.getRole());
		return set;
	}

}
